#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"

using work_t = std::function<void()>;

// 先描述
class Channel
{
public:
    Channel(int wfd, pid_t who)
        : _wfd(wfd), _who(who)
    {
        _name = "Channel-" + std::to_string(wfd) + "-" + std::to_string(who);
    }
    std::string Name()
    {
        return _name;
    }
    // 发送任务
    void Send(int cmd)
    {
        ::write(_wfd, &cmd, sizeof(cmd));
    }
    void Close()
    {
        ::close(_wfd);
    }
    pid_t Id()
    {
        return _who;
    }
    ~Channel()
    {}

private:
    int _wfd;          // 每个管道的写端
    std::string _name; // 每个管道的名字(好管理)
    pid_t _who;        // 每个子进程的pid
};

// 若用户输入的参数不对，则我提示要输入正确的信息
void Usage(std::string proc)
{
    std::cout << "Usage: " << proc << " process-num" << std::endl;
}
void Worker()
{
    while (true)
    {
        int cmd = 0;
        int n = ::read(0, &cmd, sizeof(cmd));
        if (n == sizeof(cmd)) // 若读到的字节数与cmd的字节数相等，说明读成功了
        {
            tm.Excute(cmd);
        }
        else if (n == 0)
        {
            std::cout << "pid: " << getpid() << "quit..." << std::endl;
            break;
        }
        else;
    }
}

// work_t work为回调方法
int InitProcessPool(const int &processnum, std::vector<Channel> &channels, work_t work)
{
    // 2.创建指定个数进程
    for (int i = 0; i < processnum; i++)
    {
        // 1. 先创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
            return 2;
        // 2. 再创建子进程
        pid_t id = fork();
        if (id < 0)
            return 3;
        // 3.建立信道
        if (id == 0)
        {
            // 子进程
            // 关闭历史wfd(解决bug)
            for(auto& e : channels) // 解决后续的bug
                e.Close();

            ::close(pipefd[1]); // read
            dup2(pipefd[0], 0); // 每次读数据直接从读端读入，不用再从标准输入中读
            Worker();
            ::exit(0);
        }
        // 父进程
        ::close(pipefd[0]); // write
        Channel ch(pipefd[1], id);
        channels.push_back(ch);
    }
    return 0;
}

void DispatchTask(std::vector<Channel> &channels)
{
    int who = 0;
    // 2.派发任务（以轮询方式）
    int cnt = 3;
    while (cnt--)
    {
        // a.选择一个任务，一个整数
        int task = tm.SelectTask();
        // b.选择一个子进程channel
        Channel &cur = channels[who++];
        who %= channels.size(); // 轮询子进程

        std::cout << "#####################" << std::endl;
        std::cout << "send " << task << " to" << cur.Name() << "，任务还剩：" << cnt << std::endl;
        std::cout << "#####################" << std::endl;

        // c.派发任务
        cur.Send(task);
        sleep(1);
    }
}
void CleanProcessPool(std::vector<Channel> &channels)
{
    // vison 1
    // // 关闭所有写端的fd
    // for (auto &e : channels)
    // {
    //     e.Close();
    // }
    // // 回收所有的子进程
    // for (auto &e : channels)
    // { 
    //     pid_t rid = waitpid(e.Id(), nullptr, 0);
    //     if (rid > 0)
    //     {
    //         std::cout << "child " << rid << "wait...success" << std::endl;
    //     }
    // }

    // vison 2
    // 解决一个bug，倒着关闭fd
    // 关闭所有写端的fd
    // for (int i = channels.size() - 1;i >= 0;i--)
    // {
    //     channels[i].Close();
    //     // 回收所有的子进程
    //     pid_t rid = waitpid(channels[i].Id(), nullptr, 0);
    //     if (rid > 0)
    //     {
    //         std::cout << "child " << rid << "wait...success" << std::endl;
    //     }
    // }

    // vison 3
    for (auto &e : channels)
    {
        e.Close();
        // 回收所有的子进程
        pid_t rid = waitpid(e.Id(), nullptr, 0);
        if (rid > 0)
        {
            std::cout << "child " << rid << "wait...success" << std::endl;
        }
    }
}
void DebugPrint(std::vector<Channel> &channels)
{
    for (auto &e : channels)
    {
        std::cout << e.Name() << std::endl;
    }
}
// 我们自己就是master
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    int num = std::stoi(argv[1]); // num为要创建的管道(子进程)个数

    // 将创建的管道用一个vector组织起来
    std::vector<Channel> channels;
    // 初始化进程池
    InitProcessPool(num, channels, Worker);

    // DebugPrint(channels);

    // 派发任务
    DispatchTask(channels);

    // 退出进程池
    CleanProcessPool(channels);

    return 0;
}